package com.eonmind.ai.service.impl;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.eonmind.ai.converts.AiChatConvert;
import com.eonmind.ai.core.chat.AiChatService;
import com.eonmind.ai.core.chat.model.AiChatModel;
import com.eonmind.ai.dto.AiChatDto;
import com.eonmind.ai.mapper.AiConversationMapper;
import com.eonmind.ai.mapper.AiMessageMapper;
import com.eonmind.ai.service.IAiConversationService;
import com.eonmind.common.contract.application.redis.service.RedisService;
import com.eonmind.common.contract.data.response.PageResponse;
import com.eonmind.common.contract.data.response.ResponseEntity;
import com.eonmind.common.contract.enums.ai.ConversationTypeEnum;
import com.eonmind.common.contract.enums.vip.ConsumptionTypeEnum;
import com.eonmind.common.contract.exception.BusinessException;
import com.eonmind.common.provider.dto.VipDto;
import com.eonmind.common.provider.entity.ai.AiConversation;
import com.eonmind.common.provider.entity.ai.AiConversationMessage;
import com.eonmind.common.provider.entity.ai.AiModel;
import com.eonmind.knowledge.contract.api.KnowledgeFeignService;
import com.eonmind.knowledge.contract.dto.KnowledgeData;
import com.eonmind.user.contract.dto.UserInfoData;
import com.eonmind.vip.contract.api.VipToAIFeignService;
import com.mongoplus.model.PageResult;
import com.mongoplus.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.util.List;

import static com.eonmind.common.contract.constants.ai.AiConstant.AI_CONVERSATION_MODEL_REDIS_KEY;
import static com.eonmind.common.contract.enums.ErrorCode.PARAMS_ERROR;

@Slf4j
@Service
public class AiConversationService extends ServiceImpl<AiConversation> implements IAiConversationService {
    @Resource
    private AiConversationMapper aiConversationMapper;

    @Resource
    private AiMessageMapper aiMessageMapper;


    @Autowired
    private AiChatService aiChatService;

    @Resource
    private AiModelService aiModelService;

    @Resource
    private RedisService redisService;

    @Resource
    private AiBiService aiBiService;
    @Autowired
    private KnowledgeFeignService knowledgeFeignService;
    @Resource
    private VipToAIFeignService vipToAIFeignService;

    @Override
    public PageResponse<AiChatDto.AiConversationData> pageConversation(UserInfoData userInfoData, AiChatDto.AiConversationPageRequest pageRequest) {
        PageResponse<AiChatDto.AiConversationData> pageResponse = new PageResponse<>();
        if (ObjectUtils.isEmpty(pageRequest) || ObjectUtils.isEmpty(pageRequest.getPage()) || ObjectUtils.isEmpty(userInfoData)) {
            return pageResponse;
        }

        PageResult<AiConversation> pageResult = aiConversationMapper.page(userInfoData, pageRequest);
        List<AiConversation> contentData = pageResult.getContentData();
        pageResponse.setValue(pageRequest.getPage(), pageResult.getTotalSize(), AiChatConvert.toAiConversationDataList(contentData));
        return pageResponse;
    }

    @Override
    public AiChatDto.AiConversationData createConversation(UserInfoData userInfoData, AiChatDto.AiConversationCreateRequest createRequest) {
        if (StringUtils.isBlank(createRequest.getTitle()) || ObjectUtils.isEmpty(createRequest.getType())
                || ObjectUtils.isEmpty(ConversationTypeEnum.getByCode(createRequest.getType()))) {
            throw new BusinessException(PARAMS_ERROR);
        }
        AiConversation aiConversation = new AiConversation();
        BeanUtils.copyProperties(createRequest, aiConversation);
        aiConversation.setUserId(userInfoData.getId());
        aiConversationMapper.save(aiConversation);
        AiChatDto.AiConversationData aiConversationData = AiChatConvert.toAiConversationData(aiConversation);
        return aiConversationData;
    }

    @Override
    public void editConversation(UserInfoData userInfoData, AiChatDto.AiConversationEditRequest editRequest) {
        if (ObjectUtils.isEmpty(editRequest) || ObjectUtils.isEmpty(editRequest.getId()) || ObjectUtils.isEmpty(editRequest.getTitle())) {
            throw new BusinessException(PARAMS_ERROR);
        }
        Long id = editRequest.getId();
        AiConversation aiConversation = aiConversationMapper.getById(id);
        if (ObjectUtils.isEmpty(aiConversation) || !aiConversation.getUserId().equals(userInfoData.getId())) {
            throw new BusinessException(PARAMS_ERROR);
        }
        aiConversation.setTitle(editRequest.getTitle());
        aiConversationMapper.updateById(aiConversation);
    }

    @Override
    public void delConversation(UserInfoData userInfoData, AiChatDto.AiConversationDelRequest delRequest) {
        if (ObjectUtils.isEmpty(delRequest) || ObjectUtils.isEmpty(delRequest.getId())) {
            throw new BusinessException(PARAMS_ERROR);
        }
        Long id = delRequest.getId();
        AiConversation aiConversation = aiConversationMapper.getById(id);
        if (ObjectUtils.isEmpty(aiConversation) || !aiConversation.getUserId().equals(userInfoData.getId())) {
            throw new BusinessException(PARAMS_ERROR);
        }

        aiConversationMapper.removeById(id);
    }

    public Flux<ResponseEntity<AiChatDto.AiChatData>> chatBlockHandler(
            Long userId,  // 必须与原方法参数一致
            AiChatDto.AiChatRequest aiChatRequest,  // 必须与原方法参数一致
            BlockException blockException  // 额外的 BlockException 参数
    ) {
        // 创建一个包含错误信息的响应对象
        return Flux.just(ResponseEntity.fail(
                "请求过于频繁，请稍后再试", // 错误消息
                null // 可以传递null或者自定义数据
        ));
    }


    @SentinelResource(value = "Ai-Chat", blockHandler = "chatBlockHandler")
    @Override
    public Flux<ResponseEntity<AiChatDto.AiChatData>> chat(Long userId, AiChatDto.AiChatRequest aiChatRequest) {
        // 校验参数
        if (ObjectUtils.isEmpty(aiChatRequest) || ObjectUtils.isEmpty(aiChatRequest.getConversationId())
                || ObjectUtils.isEmpty(aiChatRequest.getModelId()) || ObjectUtils.isEmpty(aiChatRequest.getModelName())
                || ObjectUtils.isEmpty(aiChatRequest.getMessage())) {
            throw new BusinessException(PARAMS_ERROR);
        }
        // 校验会话数据
        AiConversation conversation = aiConversationMapper.getById(aiChatRequest.getConversationId());
        if (ObjectUtils.isEmpty(conversation) || !conversation.getUserId().equals(userId)) {
            throw new BusinessException(PARAMS_ERROR);
        }

        Long totalToken = conversation.getTotalToken();
        if (totalToken != null && conversation.getTotalToken() >= 30000) {
            throw new BusinessException("当前会话已超过20000token，请创建新会话");
        }
        // 扣减积分
        VipDto.VipBackToAiIsAcResponse vipBackToAiIsAcResponse = decUserCost(userId, aiChatRequest);
        if (!vipBackToAiIsAcResponse.getIsAccess()) {
            throw new BusinessException(vipBackToAiIsAcResponse.getDesc());
        }
        // 校验模型数据
        AiModel model = aiModelService.selectById(aiChatRequest.getModelId());
        if (ObjectUtils.isEmpty(model) || !model.getModelName().equals(aiChatRequest.getModelName())) {
            throw new BusinessException(PARAMS_ERROR);
        }
        // 处理知识库
        String knowledgeIndexName = null;
        if (ObjectUtils.isNotEmpty(aiChatRequest.getKnowledgeId())) {
            ResponseEntity<KnowledgeData> knowledgeDataResponseEntity = knowledgeFeignService.queryKnowledge(aiChatRequest.getKnowledgeId());
            if (knowledgeDataResponseEntity.isSuccess()) {
                KnowledgeData data = knowledgeDataResponseEntity.getData();
                if (ObjectUtils.compare(data.getUserId(), userId) != 0) {
                    throw new BusinessException("知识库非法!");
                } else {
                    knowledgeIndexName = data.getIndexName();
                }
            }
        }
        // 将回话ID对应的模型数据缓存到Redis
        redisService.set(AI_CONVERSATION_MODEL_REDIS_KEY + aiChatRequest.getConversationId(), model.getId());
        aiBiService.updateUserConsumeHistory(userId, 1L, 0L, 0L, "");
        Flux<AssistantMessage> chat = aiChatService.chat(AiChatModel.builder()
                .modelId(aiChatRequest.getModelId())
                .fileList(aiChatRequest.getFileList())
                .message(aiChatRequest.getMessage())
                .model(aiChatRequest.getModelName())
                .conversationId(aiChatRequest.getConversationId())
                .assistantId(aiChatRequest.getAssistantId())
                .customSystemPrompt(aiChatRequest.getCustomSystemPrompt())
                .knowledgeIndexName(knowledgeIndexName)
                .build());

        return chat.map(AiChatConvert::toAiChatData)
                .map(ResponseEntity::success);
    }

    private VipDto.VipBackToAiIsAcResponse decUserCost(Long userId, AiChatDto.AiChatRequest aiChatRequest) {
        VipDto.VipAiServerDesc vipAiServerDesc = new VipDto.VipAiServerDesc()
                .setCost(1000)
                .setModelName(aiChatRequest.getModelName())
                .setModelId(aiChatRequest.getModelId())
                .setUserId(userId)
                .setType(ConsumptionTypeEnum.AI_CHAT.getCode());
        ResponseEntity<VipDto.VipBackToAiIsAcResponse> vipBackToAiIsAcResponseResponseEntity = vipToAIFeignService.aiServerIsAc(vipAiServerDesc);
        return vipBackToAiIsAcResponseResponseEntity.getData();
    }


    @Override
    public AiConversation selectConversationById(Long conversationIdLong) {
        return aiConversationMapper.selectById(conversationIdLong);
    }

    @Override
    public void incrementTotalToken(Long id, Integer totalTokens) {
        aiConversationMapper.incrementTotalToken(id, totalTokens);
    }


    public List<AiChatDto.AiConversationMessageData> listConversationMessages(UserInfoData userInfoData, Long conversationId) {
        // 查询对应的回话
        AiConversation aiConversation = aiConversationMapper.selectById(conversationId);
        if (ObjectUtils.isEmpty(aiConversation) || !aiConversation.getUserId().equals(userInfoData.getId())) {
            throw new BusinessException(PARAMS_ERROR);
        }
        List<AiConversationMessage> messageList = aiMessageMapper.selectByConversationId(conversationId);

        return AiChatConvert.toAiConversationMessageDataList(messageList);
    }
}
